package com.threefish.modules.sso.controller;

import com.threefish.common.annotation.ResponseJsonBody;
import com.threefish.common.plugins.shiro.LoginType;
import com.threefish.common.plugins.shiro.ShiroUserToken;
import com.threefish.common.utils.HttpClientUtil;
import com.threefish.common.utils.RedisUtils;
import com.threefish.common.utils.http.HttpJsonResponse;
import com.threefish.modules.sso.dto.SsoUserDTO;
import com.threefish.modules.sso.vo.SsoResultVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import org.nutz.json.Json;
import org.nutz.lang.Strings;
import org.nutz.lang.random.R;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;

import java.text.MessageFormat;

/**
 * @author 黄川 306955302@qq.com
 * @date: 2018/5/25
 * 描述此类：
 */
@Controller
@RequestMapping(value = "/SSO")
@Api(tags = "单点登录", description = "本系统自带的SSO")
public class SsoController {


    @Value("${sso.uniqueCode}")
    private String uniqueCode;

    @Value("${sso.validatorUrl}")
    private String validatorUrl;

    @Value("${sso.authUrl}")
    private String authUrl;

    @Autowired
    private RedisUtils redisUtils;

    private final static String SSO_PREFIX = "sso_token:";

    /**
     * 主系统--- 根据当前登录账户的信息 前往第三方系统
     */
    @GetMapping("/createToken")
    public String createToken(@RequestParam(value = "user") String userName) {
        /**
         * TODO 模拟账户应该改为正确逻辑
         */
        SsoUserDTO ssoUser = new SsoUserDTO(userName, "12316546546556565");
        //session中取得用户信息 并生成 短效token
        String token = R.UU16();
        //将token放入redis中设置时间5分钟失效
        redisUtils.set(SSO_PREFIX.concat(token), ssoUser, 5 * 60);
        return "redirect:" + MessageFormat.format(authUrl, token, uniqueCode);
    }

    /**
     * 单点登录服务器请求认证的地址
     * 主系统--- 验证并返回用户名
     */
    @GetMapping("/Validator")
    @ResponseJsonBody(nullAsEmtry = true)
    @ApiOperation("服务器后端认证地址")
    public SsoResultVO validator(@RequestParam(value = "token", defaultValue = "") String token,
                                 @RequestParam(value = "uniqueCode", defaultValue = "") String uniqueCode) {
        if (Strings.isEmpty(token) || Strings.isEmpty(uniqueCode)) {
            return SsoResultVO.error("参数不完整");
        }
        String redisKey = SSO_PREFIX.concat(token);
        if (!redisUtils.hasKey(redisKey)) {
            return SsoResultVO.error("验证信息已过期！");
        }
        SsoUserDTO user = redisUtils.get(redisKey, SsoUserDTO.class);
        redisUtils.delete(redisKey);
        return SsoResultVO.sucess(user.getUserName(), user.getIdCard());
    }

    /**
     * 单点登录用户认证的地址
     * 从系统请求我系统-我系统得到token通过后台http访问从系统进行认证，认证成功执行登录逻辑，认证失败返回消息
     */
    @GetMapping("/auth")
    @ApiOperation("单点登录用户认证地址")
    public ModelAndView auth(@RequestParam(value = "token", defaultValue = "") String token,
                             @RequestParam(value = "uniqueCode", defaultValue = "") String uniqueCode, ModelAndView model) {
        try {
            model.setViewName("sso/AuthFailed.html");
            if (Strings.isEmpty(token) || Strings.isEmpty(uniqueCode)) {
                model.addObject("errmsg", "参数不完整");
            } else {
                String url = MessageFormat.format(validatorUrl, token, uniqueCode);
                HttpJsonResponse res = HttpClientUtil.get(url);
                if (res.isOk()) {
                    SsoResultVO result = Json.fromJson(SsoResultVO.class,res.getContent());
                    if (result.getSuccess()) {
                        ShiroUserToken shiroUserToken = new ShiroUserToken(result.getUserName(), "", LoginType.SSO);
                        Subject user = SecurityUtils.getSubject();
                        user.login(shiroUserToken);
                        model.addObject("userName", result.getUserName());
                        model.setViewName("sso/AuthSucess.html");
                    } else {
                        model.addObject("errmsg", result.getErrorMessage());
                    }
                } else {
                    model.addObject("errmsg", "发送认证请求失败！可能是对方服务器无应答！");
                }
            }
        } catch (Exception e) {
            model.addObject("errmsg", e.getLocalizedMessage());
        }
        return model;
    }

}
